//Mark O Meara
//08332240

import tcdIO.Terminal;
public class Sender implements Runnable {

	public static int FRAMESIZE= 1000;			// size of frames the sender handles
	
	Channel in, out= null;		// channel in: for incoming information/frames, channel out: for outgoing information/frames
	byte[] msg,previousframe= null;		// buffer for the message that is to be send, also place to store previous frame
	int tobesent = 0;
	boolean complete = false;
	Terminal terminal1 = new Terminal("Sender");
	
	
	/*
	 * Constructor that accepts incoming and outgoing channels.
	 */
	Sender(Channel in, Channel out) {
		this(in, out, new byte[FRAMESIZE]);
	}
	

	/*
	 * Constructor that accepts incoming and outgoing channels.
	 */
	Sender(Channel in, Channel out, byte[] msg) {
		this.in= in;
		this.out= out;
		this.msg= msg;
	}
	
	
	/**
	 * Thread that attempts to send the message through the 
	 * outgoing channel.
	 */
	public class sendingThread implements Runnable {
		public void run() {
			byte[] buffer; //Used to store one frame at a time
			int index= 0;
			int framenumber = 0;
			
			/*
			 * I add 1 to the length of buffer so that I can insert a byte for the frame number
			 */

			//While not at end of msg
			while(index<msg.length || tobesent == (int)previousframe[0]) {						// depending on the remaining data 
				terminal1.println("While loop sender sending");
				//If previous from got acknowledgement:
				if(framenumber == tobesent){
					if ((index + FRAMESIZE)>=msg.length) {		// send either a full frame or the
						buffer= new byte[(msg.length-index) + 1];		// remained
					}
					else{
						buffer= new byte[FRAMESIZE + 1];
					}
					
					terminal1.println("Sender: " + index);	// debug info
					buffer[0] = (byte)framenumber;
					System.arraycopy(msg, index, buffer, 1, buffer.length - 1);//(src,srcPos,dest,destPos,length - first byte for frame num)
					terminal1.println("Sending frame number " + (int)buffer[0]);
					out.send(buffer);//Channel 1
					//index+= buffer.length;
					index = (index + buffer.length - 1);//Take away 1 to exclude frame number
					
					/*
					 * Save previous frame for re-sending:
					 */
					previousframe = new byte[buffer.length];
					previousframe = buffer;
					//Make sequence numbers wrap around
					framenumber++;
				}
				else{
					terminal1.println("Re-sending frame: " + (int)previousframe[0] + " To be sent: " + tobesent);
					out.send(previousframe);
				}
			}
			complete = true;
			terminal1.println("Sending complete");
		}
	}
	
	
	/*
	 * Thread that attempts to receive information through the 
	 * incoming channel.
	 */
	public class receivingThread implements Runnable {
		public void run() {
			while(!complete){
				byte[] next = new byte[1];
				next = in.receive();
				tobesent = (int)next[0];
			}
		}			
	}	
	
	
	/*
	 * Main method of the Sender thread that starts the sending threat
	 * and the receiving threat.
	 */
	public void run() {
		(new Thread(new receivingThread(),"Sender's receiving thread")).start();	
		(new Thread(new sendingThread(),"Sender's sending thread")).start();	
	}	
}